/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under Ultimate Liberty license
  * SLA0044, the "License"; You may not use this file except in compliance with
  * the License. You may obtain a copy of the License at:
  *                             www.st.com/SLA0044
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "fatfs.h"
#include "usb_device.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "dev.h"
#include "gui.h"
#include "boot.h"
#include "crc.h"
/* USER CODE END Includes */
unsigned int head_app_0 = 0xfabc2747;
unsigned int head_app_1 = 0xb546ee89;
	
static unsigned char rec_buffer[ 4096 * 2];
static unsigned char send_buffer[256];
static unsigned char app_data[4096];
/* decfe */
extern const unsigned int __FS_version_export[3];
/* decode */
void comdat_decode(unsigned char * dat,unsigned int len)
{
	for( unsigned int i = 0 ; i < len ; i ++)
	{
		com_char(dat[i]);
	}
}
/* void */
void com_char(unsigned char c)
{
	/* ste */
	static unsigned char step = 0;
	static unsigned char ID;
	static unsigned char ACK;
	static unsigned short len;
	static unsigned short cnt;
	static unsigned char crc[2];
	/* step */
	switch(step)
	{
		case 0:
			if( c == EASYLINK_0 )
			{
				step = 1;
				rec_buffer[0] = c;
			}
			else
			{
				step = 0;
			}
			break;
		case 1:
			if( c == EASYLINK_1 )
			{
				step = 2;
				rec_buffer[1] = c;
			}
			else
			{
				step = 0;
			}
			break;
		case 2:
			if( c == EASYLINK_2 )
			{
				step = 3;
				rec_buffer[2] = c;
			}
			else
			{
				step = 0;
			}
			break;
		case 3:
			if( c == EASYLINK_3 )
			{
				step = 4;
				rec_buffer[3] = c;
			}
			else
			{
				step = 0;
			}
			break;
		case 4:
			ID = c;
			step = 5;
			rec_buffer[4] = c;
			break;
		case 5:
			ACK = c;
			rec_buffer[5] = ACK;
			step = 6;
			break;
		case 6:
			len = c;
			rec_buffer[6] = c;
			step = 7;
			break;
		case 7:
			len |= c<<8;
			rec_buffer[7] = c;
			step = 8;
			cnt = 0;
			break;
		case 8:
			/* lcen */
			if( cnt < len )
			{
				rec_buffer[ cnt + 8 ] = c;
				/* cnt */
				cnt ++;
				/* limit */
				if( cnt >= (sizeof(rec_buffer) - 10 ) )
				{
					cnt = 0;
					step = 0;
					break;
				}
				/* get */
				if( cnt >= len )
				{
					step = 9;
				}
			}else
			{
				step = 9;
			}
			break;
		case 9:
			crc[0] = c;
			step = 10;
			rec_buffer[len + 8] = c;
			break;
		case 10:
			crc[1] = c;
			step = 0;
			rec_buffer[len + 8 + 1] = c;
			/* check */
			if( holder_check_crc( rec_buffer ,len + 8 ) == ((crc[1] << 8)|crc[0]))
			{
				/* ok */
				step = 0;
				/* decode */
				decode_com_data(ID,&rec_buffer[8],len);
				/* ------ */
			}
			/* --- */
			/* */
			break;
		default:
			step = 0;
			break;
	}
}
/* easy lnik */
int create_easylink_package(unsigned char ID ,unsigned char ACK, void * dst , unsigned short len)
{
	unsigned short crc;
	/* set head msg */
	send_buffer[0] = EASYLINK_0;
	send_buffer[1] = EASYLINK_1;
	send_buffer[2] = EASYLINK_2;
	send_buffer[3] = EASYLINK_3;
	/* set ID */
	send_buffer[4] = ID;
	/* ACK */
	send_buffer[5] = ACK;
	/* len */
	send_buffer[6] = (unsigned char)len;
	send_buffer[7] = (unsigned char)(len>>8);
	/* set cnd */
	memcpy(&send_buffer[8],dst,len);
	/* CRC */
	crc = holder_check_crc( send_buffer ,len + 8 );
	/* send buffer */
	send_buffer[ len + 8 ] = crc & 0xff;
	/* send buffer */
	send_buffer[ len + 8 + 1] = crc >> 8;
	/* return */
	return len + 8 + 2;
}
/* connect */
void boot_set_link(void)
{
	/* create buffer */
	unsigned int link_param = __FS_version_export[1];
	/* ------------- */
	int len = create_easylink_package(0xff,0,&link_param,4);
	/* send */
	usart1_send(send_buffer,len);	
	/* send */
}
void ack_link(unsigned int fd)
{
	static unsigned char ack = 0;
	/* create buffer */
	unsigned int link_param = fd;
	/* ------------- */
	int len = create_easylink_package(0,ack,&link_param,4);
	/* send */
	usart1_send(send_buffer,len);	
	usart1_send(send_buffer,len);
	usart1_send(send_buffer,len);
	/* ack */
	ack++;
	/* send */
}
/* req */
void req_link(unsigned int fd,unsigned int size)
{
	static unsigned char ack = 0;
	/* create buffer */
	unsigned int link_param[2] = {fd,size};
	/* ------------- */
	int len = create_easylink_package(3,ack,&link_param,sizeof(link_param));
	/* send */
	usart1_send(send_buffer,len);	
	usart1_send(send_buffer,len);
	usart1_send(send_buffer,len);
	/* ack */
	ack++;
	/* send */
}
/* flasg */
static unsigned int bin_size;
static unsigned int start_addr;
static unsigned char erase_flags = 0;
static unsigned int acnt = 0;
static unsigned int req_data_addr = 0;
static unsigned int get_req_data = 0;
static unsigned int ok_ack_cnt = 0;
/* decode */
void decode_com_data(unsigned char ID,unsigned char * recb,unsigned short len)
{
	/* tme */
	unsigned int * fe;
	/* ID */
	switch(ID)
	{
		case 0xff:
			/* link cmd ack */
			boot_set_link();
		  /* link */
		  boot_mode(2);
		  /* set link */
			show_string("->connect to PC");
			/*--------------*/
			break;
		case 0:
			/* get app data */
			ack_link(0);
			/* heart */
			break;
		case 1:
			/* file size and start erase */
			if( len == 8 )
			{
				unsigned int * tp = (unsigned int *)recb;
				/* check */
				bin_size = tp[0];
				start_addr = tp[1];
				/* set ack */
				ack_link(1);
				/* erase_flags */
				erase_flags = 1;
				/* ches */
				char bff[64];
				/* transfer */
				sprintf(bff,"->erasing...,fm size = %dByte,start addr = 0x%08X",bin_size,start_addr);
				/* erase */
				show_string(bff);
			}
			/*-------------------------- */
			break;
		case 2:
			/* erase_flags */
			if( erase_flags == 2 )
			{
				erase_flags = 3;
			}
			break;
			/* case */
		case 3:
			/* get add data */ 
		  if( len != 512 + 4 )
			{
				return;
			}
		  /* ------------ */
			fe = (unsigned int *)recb;
			/* check */
			if( *fe == req_data_addr )
			{
				/* ok */
				get_req_data = 1;
				/* copy data */
				memcpy( app_data , recb + 4 , len - 4 );
			}
			/* endf */
			break;
		default:
			break;
	}
}
/* USER CODE BEGIN 0 */
#define ENABLE_INT()   __set_PRIMASK(0)
#define DISABLE_INT()  __set_PRIMASK(1)
/* JumpToBootloader */
void JumpToapp(void)
{
	/* define */
	unsigned int i=0;
	void (*SysMemBootJump)(void); 
	__IO unsigned int BootAddr = 0x08020000; /* STM32H7  APP  */

	/* DISABLE INT */
	DISABLE_INT();

	/* SYSTICK DISABLE */
	SysTick->CTRL = 0;
	SysTick->LOAD = 0;
	SysTick->VAL = 0;
  /* RCC DeInit */
	//HAL_RCC_DeInit();
  /* disable all it */
	for (i = 0; i < 8; i++)
	{
		NVIC->ICER[i]=0xFFFFFFFF;
		NVIC->ICPR[i]=0xFFFFFFFF;
	}
  /* enable int */
	ENABLE_INT();

	/* bootLoader MSP + 4 */
	SysMemBootJump = (void (*)(void)) (*((uint32_t *) (BootAddr + 4)));
	/* set MSP */
	__set_MSP(*(unsigned int *)BootAddr);
	__set_CONTROL(0);
  /* jump */
	SysMemBootJump();
	/* never arrival here */
	while (1)
	{
		
	}
}
/* app check */
unsigned int app_code_check(void)
{
	/* get version addr */
	unsigned int * cde = (unsigned int *)0x08020000;
	/* check hold 256KB */
	for( int i = 0 ; i < 0x40000 / 4 ; i ++ )
	{
		/* get app version */
		if( cde[i] == head_app_0 && cde[i+2] == head_app_1)
		{
			return cde[i+1];
		}
	}
	/* return error */
	return 0;
}
/* boot loader thread */
void boot_loader_thread(void)
{
	/* erase */
	if( erase_flags == 1 )
	{
		/* erase */
		HAL_FLASH_Unlock();
		/* erase */
		if( bin_size > 0x20000 )
		{
			FLASH_Erase_Sector(1,FLASH_BANK_1,FLASH_VOLTAGE_RANGE_3);
			FLASH_Erase_Sector(2,FLASH_BANK_1,FLASH_VOLTAGE_RANGE_3);
		}
		else
		{
			FLASH_Erase_Sector(1,FLASH_BANK_1,FLASH_VOLTAGE_RANGE_3);
		}
		/* OK */
		/* set ack */
		ack_link(2);		
		/* link */
		show_string("->erase ok");
		show_string_static("->programing...");
		/* erase is ok */
		erase_flags = 2;
	}
	/* set link */
	if( erase_flags == 2 )
	{
		/* cnt */
		if( acnt++ >= 200000 )
		{
			/* set ack */
			ack_link(2);
			/* ---- */
			acnt = 0;
		}
	}
	/* progmare */
	if( erase_flags == 3 )
	{
		/* get data */
		if( get_req_data == 1 )
		{
			/* prommrak */
			get_req_data = 0;
			/* for */
			for( int i = 0 ; i < 512 / 32 ; i ++ )
			{
				/* promger */
				HAL_FLASH_Program(32,start_addr + req_data_addr + i * 32 ,(unsigned int)&app_data[i*32]);
				/* progmer */
			}
			/* req_data_addr */
			req_data_addr += 512;
			/* che */
			char bufe[32];
			/* transfer */
			sprintf(bufe,"->programing...%dByte",req_data_addr);
			/* show */
			show_string_static(bufe);
			/* over */
			if( req_data_addr >= bin_size )
			{
				erase_flags = 4;
				show_string("");
				show_string("->Successful");
			}
			/* ----------- */
		}
		/* cnt */
		if( acnt++ >= 200000 && erase_flags != 4)
		{
			/* requit data */
			req_link(req_data_addr,512);
			/* ---- */
			acnt = 0;
		}		
	}
	/* programe ok */
	if( erase_flags == 4 )
	{
		/* cnt */
		if( acnt++ >= 200000 )
		{
			/* set ack */
			ack_link(3);
			/* ---- */
			acnt = 0;
			/* ok_ack_cnt ++ */
			ok_ack_cnt ++;
			/* jump */
			show_string_static("->jump to app");
			/* if ok */
			if( ok_ack_cnt >= 3 )
			{
				/* chek */
				erase_flags = 5;
				/* jump to app */
				JumpToapp();
				/* jump */
			}
		}		
	}
	/* */
}












